package ch.unifr.diuf.webeng.taskmap.client;


import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import ch.unifr.diuf.webeng.taskmap.shared.FieldVerifier;

import ch.unifr.diuf.webeng.taskmap.client.GreetingService;
import ch.unifr.diuf.webeng.taskmap.client.GreetingServiceAsync;

import com.google.gwt.cell.client.DatePickerCell;
import com.google.gwt.cell.client.EditTextCell;
import com.google.gwt.cell.client.FieldUpdater;
import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.JsArray;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.event.dom.client.KeyUpEvent;
import com.google.gwt.event.dom.client.KeyUpHandler;
import com.google.gwt.maps.client.InfoWindowContent;
import com.google.gwt.maps.client.MapUIOptions;
import com.google.gwt.maps.client.MapWidget;
import com.google.gwt.maps.client.Maps;
import com.google.gwt.maps.client.control.LargeMapControl;
import com.google.gwt.maps.client.event.InfoWindowCloseClickHandler;
import com.google.gwt.maps.client.event.MapClickHandler;
import com.google.gwt.maps.client.geocode.Geocoder;
import com.google.gwt.maps.client.geocode.LocationCallback;
import com.google.gwt.maps.client.geocode.Placemark;
import com.google.gwt.maps.client.geocode.StatusCodes;
import com.google.gwt.maps.client.geom.LatLng;
import com.google.gwt.maps.client.overlay.Marker;
import com.google.gwt.user.cellview.client.CellTable;
import com.google.gwt.user.cellview.client.Column;
import com.google.gwt.user.cellview.client.HasKeyboardSelectionPolicy.KeyboardSelectionPolicy;
import com.google.gwt.user.cellview.client.SimplePager;
import com.google.gwt.user.cellview.client.TextColumn;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.CheckBox;
import com.google.gwt.user.client.ui.DialogBox;
import com.google.gwt.user.client.ui.DockLayoutPanel;
import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.HTMLTable.CellFormatter;
import com.google.gwt.user.client.ui.HTMLTable.RowFormatter;
import com.google.gwt.user.client.ui.HasHorizontalAlignment;
import com.google.gwt.user.client.ui.HasVerticalAlignment;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.PasswordTextBox;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.datepicker.client.DatePicker;
import com.google.gwt.view.client.AsyncDataProvider;
import com.google.gwt.view.client.HasData;
import com.google.gwt.view.client.ProvidesKey;



/*
 * Entry point classes define <code>onModuleLoad()</code>.
 */
public class TaskMap implements EntryPoint {
	/**
	 * The message displayed to the user when the server cannot be reached or
	 * returns an error.
	 */
	private static final String SERVER_ERROR = "An error occurred while "
		+ "attempting to contact the server. Please check your network "
		+ "connection and try again.";

	/**
	 * Create a remote service proxy to talk to the server-side Greeting service.
	 */
	private final GreetingServiceAsync greetingService = GWT
	.create(GreetingService.class);

	private  MapWidget map = null;

	private final ArrayList<Task> TASKS = new ArrayList<Task>();

	private Marker temporaryMarker;

	private final TextBox mapTitleField = new TextBox();
	private final HTML mapTitleErrorLabel = new HTML();
	private final TextBox mapAddressField = new TextBox();
	private final HTML mapAddressErrorLabel = new HTML();
	private final Label taskStartTimeLabel = new Label("Start time: ");
	private final TextBox mapStartTimeHourField = new TextBox();
	private final HTML mapStartTimeHourErrorLabel = new HTML();
	private final TextBox mapStartTimeMinutesField = new TextBox();
	private final HTML mapStartTimeMinutesErrorLabel = new HTML();
	private final Label taskEndTimeLabel = new Label("End time: ");
	private final TextBox mapEndTimeHourField = new TextBox();
	private final HTML mapEndTimeHourErrorLabel = new HTML();
	private final TextBox mapEndTimeMinutesField = new TextBox();
	private final HTML mapEndTimeMinutesErrorLabel = new HTML();
	private final CheckBox mapWholeDay = new CheckBox("Whole day");
	private final DatePicker mapTaskDatePicker = new DatePicker();
	private final Button mapAddButton = new Button("Add task");

	// GWT module entry point method.
	public void onModuleLoad() {//panel to order the login section, if you can make it better looking change it.
		HTML welcomeTitle = new HTML("<h1>Welcome to TaskMap</h1>");
		RootPanel.get("welcomeContainer").add(welcomeTitle);
		HTML welcomeText = new HTML("<p>Welcome on the TaskMap homepage!</p><p>You can login to view your saved task by using the login form in the upper right corner.</p><p>If you are a new user you can click on the 'Registration' button.</p>");
		RootPanel.get("welcomeContainer").add(welcomeText);

		//		RootPanel.get("content").setVisible(false);

		//		final DialogBox registerBox = new DialogBox();
		//		registerBox.addStyleName("registerDialogBox");
		//		registerBox.setText("Insert registration data");
		//		registerBox.setAnimationEnabled(true);
		//		final Button closeButton = new Button("Close");
		//		final HTML registrationWindowLabel = new HTML();
		//		VerticalPanel dialogVPanel = new VerticalPanel();
		//		dialogVPanel.addStyleName("dialogVPanel");
		//		dialogVPanel.add(registrationWindowLabel);
		//		dialogVPanel.setHorizontalAlignment(VerticalPanel.ALIGN_RIGHT);
		//		dialogVPanel.add(closeButton);
		//		registerBox.setWidget(dialogVPanel);

		VerticalPanel vertPan = new VerticalPanel();
		Label userNameLabel = new Label("Login");
		Label passLabel = new Label("Password");
		HorizontalPanel buttons = new HorizontalPanel();
		final Button loginButton = new Button("Login");
		loginButton.setStyleName("floatLeft");
		final Button registerButton = new Button("Register");
		registerButton.setStyleName("floatRight");
		final TextBox userName = new TextBox();
		// PasswordTextBox for the password
		final PasswordTextBox txtPass=new PasswordTextBox();
		//Error Label
		final Label lblError=new Label();
		vertPan.add(userNameLabel);
		vertPan.add(userName);
		vertPan.add(passLabel);
		vertPan.add(txtPass);
		vertPan.add(lblError);
		buttons.add(loginButton);
		buttons.add(registerButton);

		vertPan.add(buttons);

		RootPanel.get("loginContainer").add(vertPan);
		loginButton.addClickHandler(new ClickHandler() {
			@Override
			public void onClick(ClickEvent event) {
				if( userName.getText().trim().equals("user") && txtPass.getText().equals("password")){
					RootPanel.get("welcomeContainer").setVisible(false);
					//					RootPanel.get("content").setVisible(true);
					lblError.setText("");
					loadAfterLogin();
				}
				else{
					lblError.setText("Please enter a valid Username and Password");
					//Here some message that user doesn't exist
				}
			}
		});
		registerButton.addClickHandler(new ClickHandler() {
			@Override
			public void onClick(ClickEvent event) {
				//				registerBox.setText("Registration");
				//				registrationWindowLabel.addStyleName("serverResponseLabelError");
				//				registrationWindowLabel.setHTML(SERVER_ERROR);
				//				registerBox.center();
				//				closeButton.setFocus(true);
			}
		});
	}

	@SuppressWarnings("deprecation")
	public void loadAfterLogin(){
		RootPanel.get("loginContainer").setVisible(false);

		// The test data to display
		TASKS.add(new Task("Project meeting 1", "Bd de perolles 90, Fribourg", new Date(110, 10, 05), "12:00", "14:00"));
		TASKS.add(new Task("Get milk", "Av de la Gare 6, Fribourg", new Date(110, 10, 10), "18:00", "18:30"));
		TASKS.add(new Task("Project meeting 2", "Bd de perolles 90, Fribourg", new Date(110, 11, 3), "13:00", "14:00"));
		TASKS.add(new Task("Project report hand-in", "Bd de Perolles 90, Fribourg", new Date(110, 11, 13), "21:30", "22:00"));
		TASKS.add(new Task("Project presentation", "Bd de Perolles 90, Fribourg", new Date(110, 11, 17), "14:00", "17:00"));
		TASKS.add(new Task("Some task", "Rue de la Lenda 9, Fribourg", new Date(110, 11, 20), "9:00", "10:00"));
		TASKS.add(new Task("Some other task", "Rte de Berne, Fribourg", new Date(110, 11, 21), "11:00", "12:00"));
		TASKS.add(new Task("And one more", "Bd de Perolles 1, Fribourg", new Date(110, 11, 22), "14:00", "15:00"));

		/**
		 * The key provider that allows us to identify Contacts even if a field
		 * changes. We identify contacts by their unique ID.
		 */
		final ProvidesKey<Task> KEY_PROVIDER = new ProvidesKey<Task>() {
			public Object getKey(Task item) {
				return item.id;
			}
		};


		final CellTable<Task> cellTable = new CellTable<Task>(KEY_PROVIDER);
		cellTable.setKeyboardSelectionPolicy(KeyboardSelectionPolicy.ENABLED);
		cellTable.setPageSize(5);


		AsyncDataProvider<Task> provider = new AsyncDataProvider<Task>() {
			@Override
			protected void onRangeChanged(HasData<Task> display) {
				int start = display.getVisibleRange().getStart();
				int end = start + display.getVisibleRange().getLength();
				end = end >= TASKS.size() ? TASKS.size() : end;
				List<Task> sub = TASKS.subList(start, end);
				updateRowData(start, sub);
			}
		};
		provider.addDataDisplay(cellTable);
		provider.updateRowCount(TASKS.size(), true);

		// Create a Pager to control the table.
		SimplePager pager = new SimplePager();
		pager.setDisplay(cellTable);

		VerticalPanel vp = new VerticalPanel();
		vp.add(cellTable);
		vp.add(pager);

		// Title column
		final EditTextCell titleCell = new EditTextCell();
		Column<Task, String> titleColumn = new Column<Task, String>(titleCell) {
			@Override
			public String getValue(Task object) {
				return object.taskTitle;
			}
		};
		cellTable.addColumn(titleColumn, "Title");

		// Add a field updater to be notified when the user enters a new name
		titleColumn.setFieldUpdater(new FieldUpdater<Task, String>() {
			public void update(int index, Task object, String value) {
				// Validate the data
				if (value.length() < 3) {
					Window.alert("The title must be at least three characters long.");

					/*
					 * Clear the view data. The view data contains the pending change and
					 * allows the table to render with the pending value until the data is
					 * committed. If the data is committed into the object, the view data
					 * is automatically cleared out. If the data is not committed because
					 * it is invalid, you must delete.
					 */
					titleCell.clearViewData(KEY_PROVIDER.getKey(object));

					// Redraw the table
					cellTable.redraw();
					return;
				}

				// Inform the user of the change
				//Window.alert("You successfully changed the title of " + object.taskTitle + " to " + value);

				// Push the changes into the Task. At this point, you could send an
				// asynchronous request to the server to update the database
				object.taskTitle = value;

				// Redraw the table with the new data
				cellTable.redraw();
			}
		});

		// Address column
		final EditTextCell addressCell = new EditTextCell();
		Column<Task, String> addressColumn = new Column<Task, String>(addressCell) {
			@Override
			public String getValue(Task object) {
				return object.taskAddress;
			}
		};
		cellTable.addColumn(addressColumn, "Address");

		// Add a field updater to be notified when the user enters a new name
		addressColumn.setFieldUpdater(new FieldUpdater<Task, String>() {
			public void update(int index, Task object, String value) {
				// Validate the data
				if (value.length() < 5) {
					Window.alert("The Address must be at least five characters long.");

					/*
					 * Clear the view data. The view data contains the pending change and
					 * allows the table to render with the pending value until the data is
					 * committed. If the data is committed into the object, the view data
					 * is automatically cleared out. If the data is not committed because
					 * it is invalid, you must delete.
					 */
					addressCell.clearViewData(KEY_PROVIDER.getKey(object));

					// Redraw the table
					cellTable.redraw();
					return;
				}

				// Inform the user of the change
				//Window.alert("You successfully changed the address of " + object.taskAddress + " to " + value);

				// Push the changes into the Task. At this point, you could send an
				// asynchronous request to the server to update the database
				object.taskAddress = value;

				// Redraw the table with the new data
				cellTable.redraw();
			}
		});

		// Date column
		Column<Task, Date> dateColumn = new Column<Task, Date>(
				new DatePickerCell()) {
			@Override
			public Date getValue(Task object) {
				return object.taskDate;
			}
		};
		cellTable.addColumn(dateColumn, "Date");

		// Add a field updater to be notified when the user enters a new date
		dateColumn.setFieldUpdater(new FieldUpdater<Task, Date>() {
			public void update(int index, Task object, Date value) {
				//	        Window.alert("You changed the date of "
				//	            + object.taskTitle
				//	            + " to "
				//	            + DateTimeFormat.getFormat(PredefinedFormat.DATE_LONG).format(value));

				// Push the changes into the Contact.
				object.taskDate = value;

				// Redraw the table with the new data.
				cellTable.redraw();
			}
		});

		// Start time column
		final EditTextCell startTimeCell = new EditTextCell();
		Column<Task, String> startTimeColumn = new Column<Task, String>(startTimeCell) {
			@Override
			public String getValue(Task object) {
				return object.taskStartTime;
			}
		};
		cellTable.addColumn(startTimeColumn, "Start");

		// Add a field updater to be notified when the user enters a new name
		startTimeColumn.setFieldUpdater(new FieldUpdater<Task, String>() {
			public void update(int index, Task object, String value) {
				// Validate the data
				if(!value.equals("-") && !FieldVerifier.isValidTime(value)) {
					Window.alert("The time must be of the form [h]h:mm.");

					/*
					 * Clear the view data. The view data contains the pending change and
					 * allows the table to render with the pending value until the data is
					 * committed. If the data is committed into the object, the view data
					 * is automatically cleared out. If the data is not committed because
					 * it is invalid, you must delete.
					 */
					startTimeCell.clearViewData(KEY_PROVIDER.getKey(object));

					// Redraw the table
					cellTable.redraw();
					return;
				}

				if(value.equals("-")){
					object.taskEndTime = "-";
				}

				// Inform the user of the change
				//Window.alert("You successfully changed the start time from " + object.taskStartTime + " to " + value);

				// Push the changes into the Task. At this point, you could send an
				// asynchronous request to the server to update the database
				object.taskStartTime = value;

				// Redraw the table with the new data
				cellTable.redraw();
			}
		});

		// End time column
		final EditTextCell endTimeCell = new EditTextCell();
		Column<Task, String> endTimeColumn = new Column<Task, String>(endTimeCell) {
			@Override
			public String getValue(Task object) {
				return object.taskEndTime;
			}
		};
		cellTable.addColumn(endTimeColumn, "End");

		// Add a field updater to be notified when the user enters a new name
		endTimeColumn.setFieldUpdater(new FieldUpdater<Task, String>() {
			public void update(int index, Task object, String value) {
				// Validate the data
				if(!value.equals("-") && !FieldVerifier.isValidTime(value)) {
					Window.alert("The time must be of the form [h]h:mm.");

					/*
					 * Clear the view data. The view data contains the pending change and
					 * allows the table to render with the pending value until the data is
					 * committed. If the data is committed into the object, the view data
					 * is automatically cleared out. If the data is not committed because
					 * it is invalid, you must delete.
					 */
					endTimeCell.clearViewData(KEY_PROVIDER.getKey(object));

					// Redraw the table
					cellTable.redraw();
					return;
				}
				
				if(value.equals("-")){
					object.taskStartTime = "-";
				}
				
				// Inform the user of the change
				//Window.alert("You successfully changed the start time from " + object.taskStartTime + " to " + value);

				// Push the changes into the Task. At this point, you could send an
				// asynchronous request to the server to update the database
				object.taskEndTime = value;

				// Redraw the table with the new data
				cellTable.redraw();
			}
		});

		// "Show" button
		// TODO Add "Show" button


		cellTable.setRowCount(TASKS.size(), true);

		// Populate table
		cellTable.setRowData(0, TASKS);



		final FlexTable t = new FlexTable();
		//
		//		// Table headers
		//		t.setText(0, 0, "Title");
		//		t.setText(0, 1, "Address");
		//		t.setText(0, 2, "Date");
		//		t.setText(0, 3, "Start");
		//		t.setText(0, 4, "End");
		//		t.setText(0, 5, "Edit");
		//		t.setText(0, 6, "Directions");
		//		// Table content
		//		t.setText(1, 0, "Meeting with big boss");
		//		t.setText(1, 1, "Bd. de Perolles 90, 1700 Fribourg");
		//		t.setText(1, 2, "13.12.2010");
		//		t.setText(1, 3, "14:00");
		//		t.setText(1, 4, "14:30");
		//		t.setWidget(1, 5, new Button("Edit"));
		//		t.setWidget(1, 6, new Button("Go!"));
		//		t.setText(2, 0, "Meet someone somewhere somehow...");
		//		t.setText(2, 1, "Rue de Fribourg, 1000 Lausanne");
		//		t.setText(2, 2, "06.12.2010");
		//		t.setText(2, 3, "11:30");
		//		t.setText(2, 4, "12:30");
		//		t.setWidget(2, 5, new Button("Edit"));
		//		t.setWidget(2, 6, new Button("Go!"));

		RowFormatter rowFormatter = t.getRowFormatter();
		rowFormatter.setStyleName(0, "tableHeader");
		CellFormatter cellFormatter = t.getCellFormatter();
		// Set the styles for the headers
		for (int colIndex=0; colIndex<7; colIndex++){
			cellFormatter.setStyleName(0, colIndex, "headerStyle");
			cellFormatter.setAlignment(0, colIndex, HasHorizontalAlignment.ALIGN_CENTER, HasVerticalAlignment.ALIGN_MIDDLE);
		}

		for(int rowIndex=1; rowIndex<4; rowIndex++){
			if(rowIndex%2 == 0){
				rowFormatter.setStyleName(rowIndex, "customRowStyle");
			}else{
				rowFormatter.setStyleName(rowIndex, "tableRow");
			}
			for (int colIndex=0; colIndex<4; colIndex++){
				cellFormatter.setStyleName(rowIndex, colIndex, "customFont");
				if(colIndex == 0 || colIndex == 1 || colIndex == 2){
					cellFormatter.setAlignment(rowIndex, colIndex, HasHorizontalAlignment.ALIGN_LEFT, HasVerticalAlignment.ALIGN_MIDDLE);
				}else if(colIndex == 3 || colIndex == 4){
					cellFormatter.setAlignment(rowIndex, colIndex, HasHorizontalAlignment.ALIGN_RIGHT, HasVerticalAlignment.ALIGN_MIDDLE);
				}
			}
		}

		RootPanel.get("existingTasksContainer").add(vp);
		//RootPanel.get("existingTasksContainer").add(t);


		final Button addButton = new Button("Add task");
		addButton.addStyleName("addButton");
		final Label taskTitleLabel = new Label("Enter task title:");
		taskTitleLabel.addStyleName("taskTitleLabel");
		final TextBox titleField = new TextBox();
		titleField.addStyleName("taskTitle");
		final HTML titleErrorLabel = new HTML();
		titleErrorLabel.addStyleName("titleErrorLabel");
		final Label taskAddressLabel = new Label("Enter task address:");
		taskAddressLabel.addStyleName("taskAddressLabel");
		final TextBox addressField = new TextBox();
		addressField.addStyleName("taskAddress");
		final HTML addressErrorLabel = new HTML();
		addressErrorLabel.addStyleName("addressErrorLabel");

		// Create two fields for inserting the start and end time
		final Label startTimeLabel = new Label("Enter start time ([h]h : mm):");
		startTimeLabel.addStyleName("startTimeLabel");
		final TextBox startTimeHourField = new TextBox();
		startTimeHourField.addStyleName("startTimeHour");
		startTimeHourField.setMaxLength(2);
		final HTML startTimeSeparator = new HTML(":");
		startTimeSeparator.addStyleName("separator");
		final TextBox startTimeMinutesField = new TextBox();
		startTimeMinutesField.addStyleName("startTimeMinutes");
		startTimeMinutesField.setMaxLength(2);
		final HTML startTimeHourErrorLabel = new HTML();
		startTimeHourErrorLabel.addStyleName("startTimeHourErrorLabel");
		final HTML startTimeMinutesErrorLabel = new HTML();
		startTimeMinutesErrorLabel.addStyleName("startTimeMinutesErrorLabel");
		final Label endTimeLabel = new Label("Enter end time ([h]h : mm):");
		endTimeLabel.addStyleName("endTimeLabel");
		final TextBox endTimeHourField = new TextBox();
		endTimeHourField.addStyleName("endTimeHour");
		endTimeHourField.setMaxLength(2);
		final HTML endTimeSeparator = new HTML(":");
		endTimeSeparator.addStyleName("separator");
		final TextBox endTimeMinutesField = new TextBox();
		endTimeMinutesField.addStyleName("endTimeMinutes");
		endTimeMinutesField.setMaxLength(2);
		final HTML endTimeHourErrorLabel = new HTML();
		endTimeHourErrorLabel.addStyleName("endTimeHourErrorLabel");
		final HTML endTimeMinutesErrorLabel = new HTML();
		endTimeMinutesErrorLabel.addStyleName("endTimeMinutesErrorLabel");
		final CheckBox wholeDay = new CheckBox("Whole day");
		wholeDay.setValue(!startTimeHourField.isEnabled());
		wholeDay.addClickHandler(new ClickHandler() {
			@Override
			public void onClick(ClickEvent event) {
				if(startTimeLabel.getStyleName().contains("grey")){
					startTimeLabel.removeStyleName("grey");
				} else {
					startTimeLabel.addStyleName("grey");
				}
				startTimeHourField.setEnabled(!wholeDay.getValue());
				startTimeMinutesField.setEnabled(!wholeDay.getValue());
				if(endTimeLabel.getStyleName().contains("grey")){
					endTimeLabel.removeStyleName("grey");
				} else {
					endTimeLabel.addStyleName("grey");
				}
				endTimeHourField.setEnabled(!wholeDay.getValue());
				endTimeMinutesField.setEnabled(!wholeDay.getValue());
			}
		});



		// Create a date picker
		final DatePicker taskDatePicker = new DatePicker();
		final Label taskDatePickerLabel = new Label();
		taskDatePickerLabel.setText("Select task date:");
		taskDatePickerLabel.addStyleName("taskDatePickerLabel");
		// Set the value in the text box when the user selects a date
		//	    taskDatePicker.addValueChangeHandler(new ValueChangeHandler<Date>() {
		//	      public void onValueChange(ValueChangeEvent<Date> event) {
		//	        Date date = event.getValue();
		//	        String dateString = DateTimeFormat.getMediumDateFormat().format(date);
		//	        text.setText(dateString);
		//	      }
		//	    });
		// Set the default value
		taskDatePicker.setValue(new Date(), true);
		taskDatePicker.addStyleName("newTaskDatePicker");


		RootPanel.get("newTaskContainerLeft").add(taskTitleLabel);
		RootPanel.get("newTaskContainerLeft").add(titleField);
		RootPanel.get("newTaskContainerLeft").add(titleErrorLabel);
		RootPanel.get("newTaskContainerLeft").add(taskAddressLabel);
		RootPanel.get("newTaskContainerLeft").add(addressField);
		RootPanel.get("newTaskContainerLeft").add(addressErrorLabel);
		RootPanel.get("newTaskContainerLeft").add(startTimeLabel);
		RootPanel.get("newTaskContainerLeft").add(startTimeHourField);
		RootPanel.get("newTaskContainerLeft").add(startTimeSeparator);
		RootPanel.get("newTaskContainerLeft").add(startTimeMinutesField);
		RootPanel.get("newTaskContainerLeft").add(startTimeHourErrorLabel);
		RootPanel.get("newTaskContainerLeft").add(startTimeMinutesErrorLabel);
		RootPanel.get("newTaskContainerLeft").add(endTimeLabel);
		RootPanel.get("newTaskContainerLeft").add(endTimeHourField);
		RootPanel.get("newTaskContainerLeft").add(endTimeSeparator);
		RootPanel.get("newTaskContainerLeft").add(endTimeMinutesField);
		RootPanel.get("newTaskContainerLeft").add(endTimeHourErrorLabel);
		RootPanel.get("newTaskContainerLeft").add(endTimeMinutesErrorLabel);
		RootPanel.get("newTaskContainerLeft").add(wholeDay);
		RootPanel.get("newTaskContainerCenter").add(taskDatePickerLabel);
		RootPanel.get("newTaskContainerCenter").add(taskDatePicker);
		RootPanel.get("newTaskContainerRight").add(addButton);

		final DialogBox dialogBox = new DialogBox();
		dialogBox.addStyleName("taskDialogBox");
		dialogBox.setText("Insert task data");
		dialogBox.setAnimationEnabled(true);
		final Button closeButton = new Button("Close");
		final HTML taskWindowLabel = new HTML();
		VerticalPanel dialogVPanel = new VerticalPanel();
		dialogVPanel.addStyleName("dialogVPanel");
		dialogVPanel.add(taskWindowLabel);
		dialogVPanel.setHorizontalAlignment(VerticalPanel.ALIGN_RIGHT);
		dialogVPanel.add(closeButton);
		dialogBox.setWidget(dialogVPanel);

		// We can set the id of a widget by accessing its Element
		closeButton.getElement().setId("closeButton");

		// Add a handler to close the DialogBox
		closeButton.addClickHandler(new ClickHandler() {
			public void onClick(ClickEvent event) {
				dialogBox.hide();
				addButton.setEnabled(true);
				addButton.setFocus(true);
			}
		});

		// Create a handler for the addButton and taskField
		class MyHandler implements ClickHandler, KeyUpHandler {
			/**
			 * Fired when the user clicks on the sendButton.
			 */
			public void onClick(ClickEvent event) {
				sendTaskToServer();
			}

			/**
			 * Fired when the user types in the taskField.
			 */
			public void onKeyUp(KeyUpEvent event) {
				if (event.getNativeKeyCode() == KeyCodes.KEY_ENTER) {
					sendTaskToServer();
				}
			}

			private void sendTaskToServer() {
				// First, we validate the input.
				final String taskName = titleField.getText().trim();
				final String taskAddress = addressField.getText().trim();
				final Date taskDate = taskDatePicker.getValue(); // TODO filter out only date (without time)
				final String taskStartHour = startTimeHourField.getText().trim();
				final String taskStartMinutes = startTimeMinutesField.getText().trim();
				final String taskEndHour = endTimeHourField.getText().trim();
				final String taskEndMinutes = endTimeMinutesField.getText().trim();
				final String taskStartTime;
				final String taskEndTime;
				if(!wholeDay.getValue()){
					taskStartTime = taskStartHour+":"+taskStartMinutes;
					taskEndTime = taskEndHour+":"+taskEndMinutes;
				}else{
					taskStartTime = "-";
					taskEndTime = "-";
				}
				titleErrorLabel.setText("");
				addressErrorLabel.setText("");
				startTimeHourErrorLabel.setText("");
				startTimeMinutesErrorLabel.setText("");
				endTimeHourErrorLabel.setText("");
				endTimeMinutesErrorLabel.setText("");
				if (!FieldVerifier.isValidTitle(taskName) || !FieldVerifier.isValidAddress(taskAddress) || (!wholeDay.getValue() && !FieldVerifier.isValidHour(taskStartHour)) || (!wholeDay.getValue() && !FieldVerifier.isValidMinute(taskStartMinutes)) || (!wholeDay.getValue() && !FieldVerifier.isValidHour(taskEndHour)) || (!wholeDay.getValue() && !FieldVerifier.isValidMinute(taskEndMinutes))) {
					if (!FieldVerifier.isValidTitle(taskName)) {
						titleErrorLabel.setText("Please enter at least three characters.");
					}
					if(!FieldVerifier.isValidAddress(taskAddress)) {
						addressErrorLabel.setText("Please enter at least five characters.");
					}
					if(!wholeDay.getValue()){
						if(!FieldVerifier.isValidHour(taskStartHour)) {
							startTimeHourErrorLabel.setText("Please enter an hour value between 00 and 24.");
						}
						if(!FieldVerifier.isValidMinute(taskStartMinutes)) {
							startTimeMinutesErrorLabel.setText("Please enter a minute value between 00 and 59.");
						}
						if(!FieldVerifier.isValidHour(taskEndHour)) {
							endTimeHourErrorLabel.setText("Please enter an hour value between 00 and 24.");
						}
						if(!FieldVerifier.isValidMinute(taskEndMinutes)) {
							endTimeMinutesErrorLabel.setText("Please enter a minute value between 00 and 59.");
						}
					}
					return;
				}

				addButton.setEnabled(false);

				greetingService.greetServer(taskName,
						//				tmd.saveTask(task,
						new AsyncCallback<String>() {
					public void onFailure(Throwable caught) {
						// Show the RPC error message to the user
						dialogBox
						.setText("Remote Procedure Call - Failure");
						taskWindowLabel
						.addStyleName("serverResponseLabelError");
						taskWindowLabel.setHTML(SERVER_ERROR);
						dialogBox.center();
						closeButton.setFocus(true);
					}

					public void onSuccess(String result) {

						// TODO add task to DB with task.addTaskToDB(task); and reload task list (now, for testing purposes, the new task is directly added to the table)
						//						int row = t.getRowCount()-1;
						//						t.setText(row, 0, taskName);
						//						t.setText(row, 1, taskAddress);
						//						t.setText(row, 2, taskDate.toString());
						//						if(!wholeDay.getValue()){
						//							t.setText(row, 3, start);
						//							t.setText(row, 4, end);
						//						}else{
						//							t.setText(row, 3, "-");
						//							t.setText(row, 4, "-");
						//						}
						//						t.setWidget(row, 5, new Button("Edit"));
						//						t.setWidget(row, 6, new Button("Go!"));


						Task task = new Task(taskName, taskAddress, taskDate, taskStartTime, taskEndTime);
						TASKS.add(task);
						cellTable.setRowData(0, TASKS);
						// TODO Check if marker already exists at this address!!!
						task.addTaskToMap(map, true);

						titleField.setText("");
						addressField.setText("");
						taskDatePicker.setValue(new Date());
						if(!wholeDay.getValue()){
							startTimeHourField.setText("");
							startTimeMinutesField.setText("");
							endTimeHourField.setText("");
							endTimeMinutesField.setText("");
						}else{
							startTimeLabel.removeStyleName("grey");
							startTimeHourField.setEnabled(true);
							startTimeMinutesField.setEnabled(true);
							endTimeLabel.removeStyleName("grey");
							endTimeHourField.setEnabled(true);
							endTimeMinutesField.setEnabled(true);
							wholeDay.setValue(false);
						}

						// Then, we send the input to the server.
						dialogBox.setText("Confirmation");
						taskWindowLabel
						.removeStyleName("serverResponseLabelError");
						taskWindowLabel.setHTML("The task <b>"+taskName+"</b> was added successfully to the database and to the map.");
						dialogBox.center();
						closeButton.setFocus(true);
					}
				});
			}
		}

		class MapHandler implements ClickHandler, KeyUpHandler {
			/**
			 * Fired when the user clicks on the sendButton on the map.
			 */
			public void onClick(ClickEvent event) {
				sendMapTaskToServer();
			}

			/**
			 * Fired when the user types in the taskField.
			 */
			public void onKeyUp(KeyUpEvent event) {
				if (event.getNativeKeyCode() == KeyCodes.KEY_ENTER) {
					sendMapTaskToServer();
				}
			}

			private void sendMapTaskToServer() {
				// First, we validate the input.
				final String taskName = mapTitleField.getText().trim();
				final String taskAddress = mapAddressField.getText().trim();
				final Date taskDate = mapTaskDatePicker.getValue(); // TODO filter out only date (without time)
				final String taskStartHour = mapStartTimeHourField.getText().trim();
				final String taskStartMinutes = mapStartTimeMinutesField.getText().trim();
				final String taskEndHour = mapEndTimeHourField.getText().trim();
				final String taskEndMinutes = mapEndTimeMinutesField.getText().trim();
				final String taskStartTime;
				final String taskEndTime;
				if(!mapWholeDay.getValue()){
					taskStartTime = taskStartHour+":"+taskStartMinutes;
					taskEndTime = taskEndHour+":"+taskEndMinutes;
				}else{
					taskStartTime = "-";
					taskEndTime = "-";
				}
				mapTitleErrorLabel.setText("");
				mapAddressErrorLabel.setText("");
				mapStartTimeHourErrorLabel.setText("");
				mapStartTimeMinutesErrorLabel.setText("");
				mapEndTimeHourErrorLabel.setText("");
				mapEndTimeMinutesErrorLabel.setText("");
				if (!FieldVerifier.isValidTitle(taskName) || !FieldVerifier.isValidAddress(taskAddress)) {
					if (!FieldVerifier.isValidTitle(taskName)) {
						mapTitleErrorLabel.setText("Please enter at least three characters.");
					}
					if(!FieldVerifier.isValidAddress(taskAddress)) {
						mapAddressErrorLabel.setText("Please enter at least five characters.");
					}
					if(!mapWholeDay.getValue()){
						if(!FieldVerifier.isValidHour(taskStartHour)) {
							mapStartTimeHourErrorLabel.setText("Please enter an hour value between 00 and 24.");
						}
						if(!FieldVerifier.isValidMinute(taskStartMinutes)) {
							mapStartTimeMinutesErrorLabel.setText("Please enter a minute value between 00 and 59.");
						}
						if(!FieldVerifier.isValidHour(taskEndHour)) {
							mapEndTimeHourErrorLabel.setText("Please enter an hour value between 00 and 24.");
						}
						if(!FieldVerifier.isValidMinute(taskEndMinutes)) {
							mapEndTimeMinutesErrorLabel.setText("Please enter a minute value between 00 and 59.");
						}
					}
					return;
				}

				addButton.setEnabled(false);

				greetingService.greetServer(taskName,
						new AsyncCallback<String>() {
					public void onFailure(Throwable caught) {
						// Show the RPC error message to the user
						dialogBox
						.setText("Remote Procedure Call - Failure");
						taskWindowLabel
						.addStyleName("serverResponseLabelError");
						taskWindowLabel.setHTML(SERVER_ERROR);
						dialogBox.center();
						closeButton.setFocus(true);
					}

					public void onSuccess(String result) {
						// TODO add task to DB with task.addTaskToDB(task); and reload task list (now, for testing purposes, the new task is directly added to the table)
						//						int row = t.getRowCount()-1;
						//						t.setText(row, 0, taskName);
						//						t.setText(row, 1, taskAddress);
						//						t.setText(row, 2, taskDate.toString());
						//						if(!mapWholeDay.getValue()){
						//							t.setText(row, 3, taskStartTime);
						//							t.setText(row, 4, taskEndTime);
						//						}else{
						//							t.setText(row, 3, "-");
						//							t.setText(row, 4, "-");
						//						}
						//						t.setWidget(row, 5, new Button("Edit"));
						//						t.setWidget(row, 6, new Button("Go!"));

						Task task = new Task(taskName, taskAddress, taskDate, taskStartTime, taskEndTime);
						TASKS.add(task);
						cellTable.setRowData(0, TASKS);
						map.removeOverlay(temporaryMarker);
						task.addTaskToMap(map, true);

						mapTitleField.setText("");
						mapAddressField.setText("");
						mapTaskDatePicker.setValue(new Date());


						if(!mapWholeDay.getValue()){
							mapStartTimeHourField.setText("");
							mapStartTimeMinutesField.setText("");
							mapEndTimeHourField.setText("");
							mapEndTimeMinutesField.setText("");
						}else{
							taskStartTimeLabel.removeStyleName("grey");
							mapStartTimeHourField.setEnabled(true);
							mapStartTimeMinutesField.setEnabled(true);
							taskEndTimeLabel.removeStyleName("grey");
							mapEndTimeHourField.setEnabled(true);
							mapEndTimeMinutesField.setEnabled(true);
							mapWholeDay.setValue(false);
						}

						// Then, we send the input to the server.
						dialogBox.setText("Confirmation");
						taskWindowLabel
						.removeStyleName("serverResponseLabelError");
						taskWindowLabel.setHTML("The task <b>"+taskName+"</b> was added successfully to the database and to the map.");
						dialogBox.center();
						closeButton.setFocus(true);
					}
				});
			}
		}


		// Add a handler to send the name to the server
		MyHandler handler = new MyHandler();
		addButton.addClickHandler(handler);
		MapHandler mapHandler = new MapHandler();
		mapAddButton.addClickHandler(mapHandler);
		titleField.addKeyUpHandler(handler);
		addressField.addKeyUpHandler(handler);


		/*
		 * Asynchronously loads the Maps API.
		 *
		 * The first parameter should be a valid Maps API Key to deploy this
		 * application on a public server, but a blank key will work for an
		 * application served from localhost.
		 */
		Maps.loadMapsApi("ABQIAAAA9DWbGC4Fa9JyrbLNt4RLBBSGNkDDF4iyAUJbV2lgc-XpYWsDGRRdaCJD8jGCwZcskTLa72uxJOorCQ", "2", false, new Runnable() {
			public void run() {
				buildUi();
			}
		});
		// TODO Find a way to set the language of the map to English

	}

	private void buildUi() {
		// Open a map centered on Fribourg, Switzerland
		LatLng uniFr = LatLng.newInstance(46.793973, 7.159018);

		//		final MapWidget 
		map = new MapWidget(uniFr, 12);

		// Workaround for bug with click handler & setUItoDefaults() - see issue 260
		MapUIOptions opts = map.getDefaultUI();
		opts.setDoubleClick(false);
		map.setUI(opts);
		map.setSize("100%", "100%");

		// Add some controls for the zoom level
		map.addControl(new LargeMapControl());

		// Add a marker
		//map.addOverlay(new Marker(uniFr));

		// Add an info window to highlight a point of interest
		//map.getInfoWindow().open(map.getCenter(),
		//		new InfoWindowContent("Perolles 21"));

		final DockLayoutPanel dock = new DockLayoutPanel(Unit.PX);
		dock.addNorth(map, 500);

		for(Task t : TASKS){
			t.addTaskToMap(map, false);
		}

		map.addMapClickHandler(new MapClickHandler() {
			Geocoder g = new Geocoder();
			public void onClick(final MapClickEvent e) {
				if(e.getOverlay()!=null){
					return;
				}

				final LatLng point = e.getLatLng();
				temporaryMarker = new Marker(point);
				final FlexTable panel = new FlexTable();
				final InfoWindowContent content = new InfoWindowContent(panel);
				HTML mapNewTaskTitle = new HTML("<h3>New task</h3>");
				mapNewTaskTitle.addStyleName("mapNewTaskTitle");
				panel.setWidget(0, 0, mapNewTaskTitle);
				panel.getFlexCellFormatter().setColSpan(0, 0, 4);
				panel.getFlexCellFormatter().setHorizontalAlignment(0, 0, HasHorizontalAlignment.ALIGN_CENTER);
				g.getLocations(point, new LocationCallback(){
					public void onFailure(int statusCode){
						Window.alert("Failed to geocode position " + e.getLatLng()
								+ ". Status: " + statusCode + " "
								+ StatusCodes.getName(statusCode));
					}
					public void onSuccess(JsArray<Placemark> locations) {
						for (int i = 0; i < locations.length(); ++i) {
							Placemark location = locations.get(i);
							StringBuilder value = new StringBuilder();
							//this example is taken from reverse geocoding
							if (location.getAddress() != null) {
								Label taskTitleLabel = new Label("Task title: ");
								mapTitleField.addStyleName("mapTaskTitle");
								mapTitleErrorLabel.addStyleName("mapTitleErrorLabel");
								panel.setWidget(1, 0, taskTitleLabel);
								panel.setWidget(1, 1, mapTitleField);
								panel.getFlexCellFormatter().setColSpan(1, 1, 3);
								panel.setWidget(2, 0, mapTitleErrorLabel);
								panel.getFlexCellFormatter().setColSpan(2, 0, 4);
								Label taskAddressLabel = new Label("Task address: ");
								mapAddressField.addStyleName("mapTaskAddress");
								value.append(location.getAddress());
								mapAddressField.setText(value.toString());
								mapAddressErrorLabel.addStyleName("mapAddressErrorLabel");
								panel.setWidget(3, 0, taskAddressLabel);
								panel.setWidget(3, 1, mapAddressField);
								panel.getFlexCellFormatter().setColSpan(3, 1, 3);
								panel.setWidget(4, 0, mapAddressErrorLabel);
								panel.getFlexCellFormatter().setColSpan(4, 0, 4);
								mapStartTimeHourField.addStyleName("mapTaskStartTimeHour");
								mapStartTimeHourField.setMaxLength(2);
								mapStartTimeHourErrorLabel.addStyleName("mapStartTimeHourErrorLabel");
								HTML startTimeSeparator = new HTML(":");
								startTimeSeparator.addStyleName("separator");
								mapStartTimeMinutesField.addStyleName("mapTaskStartTimeMinutes");
								mapStartTimeMinutesField.setMaxLength(2);
								mapStartTimeMinutesErrorLabel.addStyleName("mapStartTimeMinutesErrorLabel");
								panel.setWidget(5, 0, taskStartTimeLabel);
								panel.setWidget(5, 1, mapStartTimeHourField);
								panel.getFlexCellFormatter().setWidth(5, 1, "10%");
								panel.getFlexCellFormatter().setHorizontalAlignment(5, 1, HasHorizontalAlignment.ALIGN_RIGHT);
								panel.setWidget(5, 2, startTimeSeparator);
								panel.getFlexCellFormatter().setWidth(5, 2, "2%");
								panel.setWidget(5, 3, mapStartTimeMinutesField);
								panel.getFlexCellFormatter().setWidth(5, 3, "10%");
								panel.setWidget(6, 0, mapStartTimeHourErrorLabel);
								panel.getFlexCellFormatter().setColSpan(6, 0, 2);
								panel.setWidget(6, 2, mapStartTimeMinutesErrorLabel);
								panel.getFlexCellFormatter().setColSpan(6, 2, 2);
								mapEndTimeHourField.addStyleName("mapTaskEndTimeHour");
								mapEndTimeHourField.setMaxLength(2);
								mapEndTimeHourErrorLabel.addStyleName("mapEndTimeHourErrorLabel");
								HTML endTimeSeparator = new HTML(":");
								endTimeSeparator.addStyleName("separator");
								mapEndTimeMinutesField.addStyleName("mapTaskEndTimeMinutes");
								mapEndTimeMinutesField.setMaxLength(2);
								mapEndTimeMinutesErrorLabel.addStyleName("mapEndTimeMinutesErrorLabel");
								panel.setWidget(7, 0, taskEndTimeLabel);
								panel.setWidget(7, 1, mapEndTimeHourField);
								panel.getFlexCellFormatter().setWidth(7, 1, "10%");
								panel.getFlexCellFormatter().setHorizontalAlignment(7, 1, HasHorizontalAlignment.ALIGN_RIGHT);
								panel.setWidget(7, 2, endTimeSeparator);
								panel.getFlexCellFormatter().setWidth(7, 2, "2%");
								panel.setWidget(7, 3, mapEndTimeMinutesField);
								panel.getFlexCellFormatter().setWidth(7, 3, "10%");
								panel.setWidget(8, 0, mapEndTimeHourErrorLabel);
								panel.getFlexCellFormatter().setColSpan(8, 0, 2);
								panel.setWidget(8, 2, mapEndTimeMinutesErrorLabel);
								panel.getFlexCellFormatter().setColSpan(8, 2, 2);
								mapWholeDay.setValue(!mapStartTimeHourField.isEnabled());
								mapWholeDay.addClickHandler(new ClickHandler() {
									@Override
									public void onClick(ClickEvent event) {
										if(taskStartTimeLabel.getStyleName().contains("grey")){
											taskStartTimeLabel.removeStyleName("grey");
										} else {
											taskStartTimeLabel.addStyleName("grey");
										}
										mapStartTimeHourField.setEnabled(!mapWholeDay.getValue());
										mapStartTimeMinutesField.setEnabled(!mapWholeDay.getValue());
										if(taskEndTimeLabel.getStyleName().contains("grey")){
											taskEndTimeLabel.removeStyleName("grey");
										} else {
											taskEndTimeLabel.addStyleName("grey");
										}
										mapEndTimeHourField.setEnabled(!mapWholeDay.getValue());
										mapEndTimeMinutesField.setEnabled(!mapWholeDay.getValue());
									}
								});
								panel.setWidget(9, 0, mapWholeDay);
								Label taskDatePickerLabel = new Label();
								taskDatePickerLabel.setText("Date: ");
								taskDatePickerLabel.addStyleName("mapTaskDatePickerLabel");
								mapTaskDatePicker.setValue(new Date(), true);
								mapTaskDatePicker.addStyleName("mapTaskDatePicker");
								panel.setWidget(10, 0, taskDatePickerLabel);
								panel.setWidget(10, 1, mapTaskDatePicker);
								panel.getFlexCellFormatter().setColSpan(10, 1, 3);
								mapAddButton.addStyleName("mapAddButton");
								panel.setWidget(11, 0, mapAddButton);
								panel.getFlexCellFormatter().setColSpan(11, 0, 4);
								panel.getFlexCellFormatter().setHorizontalAlignment(11, 0, HasHorizontalAlignment.ALIGN_RIGHT);
								break;
							}

						}

						map.addOverlay(temporaryMarker);
						map.getInfoWindow().open(temporaryMarker, content);
						map.getInfoWindow().addInfoWindowCloseClickHandler(new InfoWindowCloseClickHandler() {

							@Override
							public void onCloseClick(InfoWindowCloseClickEvent event) {
								map.removeOverlay(temporaryMarker);
							}
						});
						// TODO Remove temporaryMarker if user clicks outside of its InfoWindow 
					}
				});
			}
		});
		//		Button clearMapButton = new Button("Clear map");
		//		clearMapButton.getElement().setId("clearMapButton");
		//		clearMapButton.addClickHandler(new ClickHandler() {
		//			public void onClick(ClickEvent event) {
		//				map.clearOverlays();
		//			}
		//		});
		//		dock.addNorth(clearMapButton, 50);
		// Add the map to the HTML host page
		RootPanel.get("mapContainer").add(dock);
	}
}